#pragma once

//
// Default error reporting macros.  See MyActiveObject or MyActiveHSM in RoomTemplates
//	project for example usage.
//

//
// ADD_MESSAGE_INFO_TEXT:  Add port name and message id to error string
//
//	THIS - this or me
//
//	IN_MSG - Message being handled when error was thrown
//
//	ERROR_TEXT	- std::string to add error message text to.
//
#define ADD_MESSAGE_INFO_TEXT(THIS, IN_MSG, ERROR_TEXT)																		\
{																															\
	using namespace RoomFW;																				\
	if (0 != (IN_MSG))																										\
	{																														\
		(ERROR_TEXT) += ':';																								\
		(ERROR_TEXT) += (THIS)->getPortName((IN_MSG)->portIndex().port());													\
		(ERROR_TEXT) += ':';																								\
		if (((IN_MSG)->portIndex().port() < (THIS)->timerPortIndex()) &&													\
			(THIS)->getContractChecker((IN_MSG)->portIndex().port()))														\
		{																													\
			(ERROR_TEXT) += (THIS)->getContractChecker((IN_MSG)->portIndex().port())->messageName((IN_MSG)->messageID());	\
		}																													\
		else if ((IN_MSG)->portIndex().port() == (THIS)->timerPortIndex())													\
		{																													\
			(ERROR_TEXT) += "TIMER_MESSAGE";																				\
		}																													\
		else																												\
		{																													\
			(ERROR_TEXT) += "UNKNOWN_MESSAGE";																				\
		}																													\
	}																														\
}																															\

//
// REPORT_MSG_ERROR:  Default error reporting handler for catch(IError&) in message handling.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_ERROR(THIS, SYS_PRT, IN_MSG, ERROR, PORT, OUT_MSG_ID)														\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += "<\"";																									\
	derErrorMessage += (ERROR).what();																							\
	derErrorMessage += "\">";																									\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||												\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		ErrorPayloadSP derErrorPayload(new ErrorPayload((ERROR).clone()));														\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onError((ERROR));																									\
}																																\

//
// REPORT_ERROR:  Default error reporting handler for catch(IError&)
//
//	THIS - this or me
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_ERROR(THIS, ERROR, PORT, OUT_MSG_ID) REPORT_MSG_ERROR((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (ERROR), (PORT), (OUT_MSG_ID))

//
// FORWARD_ERROR:  Default error forwarding for incoming errors.
//
//	THIS - this or me
//
//	ERROR_MESSAGE - RoomMessage{* | SP} containing an error payload.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define FORWARD_ERROR(THIS, ERROR_MESSAGE, PORT, OUT_MSG_ID)														\
{																															\
	using namespace CO::SpiControl::Protocol;																				\
	ErrorPayloadSP derInErrorPayload = boost::dynamic_pointer_cast<ErrorPayload>((ERROR_MESSAGE)->releasePayload());		\
	ASSERT(0 != derInErrorPayload);																							\
	REPORT_ERROR((THIS), *(derInErrorPayload->value()), (PORT), (OUT_MSG_ID));									\
}																															\

//
// REPORT_MSG_ERROR_EVENT:  Error reporting handler for catch(IError&) in message handling and protocols to legacy
//						that require MachineControlEvents.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_ERROR_EVENT(THIS, SYS_PRT, IN_MSG, ERROR, PORT, OUT_MSG_ID)													\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace Interface;																				\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += "<\"";																									\
	derErrorMessage += (ERROR).what();																							\
	derErrorMessage += "\">";																									\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||													\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		IMachineControlEventSP derErrorEvent(new ErrorEvent((ERROR).clone()));													\
		IPayloadSP derErrorPayload(new MachineControlEventPayload(derErrorEvent));												\
		derErrorEvent.reset();																									\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onError((ERROR));																									\
}																																\

//
// REPORT_ERROR_EVENT:  Error reporting handler for catch(IError&) and protocols to legacy
//						that require MachineControlEvents.
//
//	THIS - this or me
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_ERROR_EVENT(THIS, ERROR, PORT, OUT_MSG_ID) REPORT_MSG_ERROR_EVENT((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (ERROR), (PORT), (OUT_MSG_ID))

//
// FORWARD_ERROR_EVENT:  Default error event forwarding for incoming errors.
//
//	THIS - this or me
//
//	ERROR_MESSAGE - RoomMessage{* | SP} containing an error payload.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define FORWARD_ERROR_EVENT(THIS, ERROR_MESSAGE, PORT, OUT_MSG_ID)													\
{																															\
	using namespace CO::SpiControl::Protocol;																				\
	ErrorPayloadSP derInErrorPayload = boost::dynamic_pointer_cast<ErrorPayload>((ERROR_MESSAGE)->releasePayload());		\
	ASSERT(0 != derInErrorPayload);																							\
	REPORT_ERROR_EVENT((THIS), *(derInErrorPayload->value()), (PORT), (OUT_MSG_ID));								\
}																															\

//
// REPORT_MSG_EXCEPTION:  Default exception reporting handler for catch(std::exception&) in message handling
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_EXCEPTION(THIS, SYS_PRT, IN_MSG, EXCEPTION, PORT, OUT_MSG_ID)												\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += "<\"";																									\
	derErrorMessage += (EXCEPTION).what();																						\
	derErrorMessage += "\">";																									\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||													\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		BaseErrorSP derBaseError(new BaseError(EID_FND_UNHANDLED_EXCEPTION, ESEVfatal, derErrorMessage));						\
		ErrorPayloadSP derErrorPayload(new ErrorPayload(derBaseError));															\
		derBaseError.reset();																									\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onException((EXCEPTION));																							\
}																																\

//
// REPORT_EXCEPTION:  Default exception reporting handler for catch(std::exception&)
//
//	THIS - this or me
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_EXCEPTION(THIS, EXCEPTION, PORT, OUT_MSG_ID) REPORT_MSG_EXCEPTION((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (EXCEPTION), (PORT), (OUT_MSG_ID))

//
// REPORT_MSG_EXCEPTION_EVENT:  Default exception reporting handler for catch(std::exception&) in message handling
//							and protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_EXCEPTION_EVENT(THIS, SYS_PRT, IN_MSG, EXCEPTION, PORT, OUT_MSG_ID)											\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace Interface;																				\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += "<\"";																									\
	derErrorMessage += (EXCEPTION).what();																						\
	derErrorMessage += "\">";																									\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||													\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		BaseErrorSP derBaseError(new BaseError(EID_FND_UNHANDLED_EXCEPTION, ESEVfatal, derErrorMessage));						\
		IMachineControlEventSP derErrorEvent(new ErrorEvent(derBaseError));														\
		derBaseError.reset();																									\
		IPayloadSP derErrorPayload(new MachineControlEventPayload(derErrorEvent));												\
		derErrorEvent.reset();																									\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onException((EXCEPTION));																							\
}																																\

//
// REPORT_EXCEPTION_EVENT:  Default exception reporting handler for catch(std::exception&)
//							and protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_EXCEPTION_EVENT(THIS, EXCEPTION, PORT, OUT_MSG_ID) REPORT_MSG_EXCEPTION_EVENT((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (EXCEPTION), (PORT), (OUT_MSG_ID))

//
// REPORT_MSG_CATCH_ALL_EXCEPTION:  Default exception reporting handler for catch(...) in message handling
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_CATCH_ALL_EXCEPTION(THIS, SYS_PRT, IN_MSG, PORT, OUT_MSG_ID)													\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += ":Catch-all Exception";																					\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||													\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		BaseErrorSP derBaseError(new BaseError(EID_FND_UNHANDLED_EXCEPTION, ESEVfatal, derErrorMessage));						\
		ErrorPayloadSP derErrorPayload(new ErrorPayload(derBaseError));															\
		derBaseError.reset();																									\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onCatchAllException();																								\
}																																\

//
// REPORT_CATCH_ALL_EXCEPTION:  Default exception reporting handler for catch(...)
//
//	THIS - this or me
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_CATCH_ALL_EXCEPTION(THIS, PORT, OUT_MSG_ID) REPORT_MSG_CATCH_ALL_EXCEPTION((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (PORT), (OUT_MSG_ID))

//
// REPORT_MSG_CATCH_ALL_EXCEPTION_EVENT:  Default exception reporting handler for catch(...) in message handling
//							and protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_MSG_CATCH_ALL_EXCEPTION_EVENT(THIS, SYS_PRT, IN_MSG, PORT, OUT_MSG_ID)											\
{																																\
	using namespace ErrorHandling;																			\
	using namespace RoomFW;																					\
	using namespace Interface;																				\
	using namespace CO::SpiControl::Protocol;																					\
	std::string derErrorMessage = (THIS)->getObjectName();																		\
	ADD_MESSAGE_INFO_TEXT((THIS), (IN_MSG), derErrorMessage);																	\
	derErrorMessage += ":Catch-all Exception";																					\
	G_LOG_0_ERROR(derErrorMessage.c_str());																						\
	if ((THIS)->isBound((PORT)) &&																								\
		!(IN_MSG && ((IN_MSG)->portIndex().port() == (SYS_PRT)) &&																\
			(((IN_MSG)->messageID() == SystemManagerProtocol::HARDWARE_DISABLED_EVENT) ||										\
			((IN_MSG)->messageID() == SystemManagerProtocol::HW_ERROR_EVENT) ||													\
			((IN_MSG)->messageID() == SystemManagerProtocol::SW_ERROR_EVENT))))													\
	{																															\
		BaseErrorSP derBaseError(new BaseError(EID_FND_UNHANDLED_EXCEPTION, ESEVfatal, derErrorMessage));						\
		IMachineControlEventSP derErrorEvent(new ErrorEvent(derBaseError));														\
		derBaseError.reset();																									\
		IPayloadSP derErrorPayload(new MachineControlEventPayload(derErrorEvent));												\
		derErrorEvent.reset();																									\
		(THIS)->sendMessage((PORT), (OUT_MSG_ID), IPayload::ReleaseOwnership(derErrorPayload));									\
	}																															\
	(THIS)->onCatchAllException();																								\
}																																\

//
// REPORT_CATCH_ALL_EXCEPTION_EVENT:  Default exception reporting handler for catch(...)
//							and protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define REPORT_CATCH_ALL_EXCEPTION_EVENT(THIS, PORT, OUT_MSG_ID) REPORT_MSG_CATCH_ALL_EXCEPTION_EVENT((THIS), RoomFW::PortIndex::INVALID, RoomFW::RoomMessageSP(), (PORT), (OUT_MSG_ID))

//
// DEFAULT_CATCH_BLOCKS:  Default exception reporting catch blocks.
//
//	THIS - this or me
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define DEFAULT_CATCH_BLOCKS(THIS, PORT, OUT_MSG_ID)																\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_ERROR((THIS), e, (PORT), (OUT_MSG_ID));															\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_EXCEPTION((THIS), e, (PORT), (OUT_MSG_ID));														\
	}																														\
	catch (...)																												\
	{																														\
		REPORT_CATCH_ALL_EXCEPTION((THIS), (PORT), (OUT_MSG_ID));												\
	}																														\

//
// DEFAULT_MSG_CATCH_BLOCKS:  Default exception reporting catch blocks in message handling.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define DEFAULT_MSG_CATCH_BLOCKS(THIS, SYS_PRT, IN_MSG, PORT, OUT_MSG_ID)													\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_MSG_ERROR((THIS), (SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID));												\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_MSG_EXCEPTION((THIS), (SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID));											\
	}																														\
	catch (...)																												\
	{																														\
		REPORT_MSG_CATCH_ALL_EXCEPTION((THIS), (SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID));									\
	}																														\

//
// DEFAULT_CATCH_BLOCKS_EVENT:  Default exception reporting catch blocks for
//								protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define DEFAULT_CATCH_BLOCKS_EVENT(THIS, PORT, OUT_MSG_ID)															\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_ERROR_EVENT((THIS), e, (PORT), (OUT_MSG_ID));														\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_EXCEPTION_EVENT((THIS), e, (PORT), (OUT_MSG_ID));													\
	}																														\
	catch (...)																												\
	{																														\
		REPORT_CATCH_ALL_EXCEPTION_EVENT((THIS), (PORT), (OUT_MSG_ID));											\
	}																														\

//
// DEFAULT_MSG_CATCH_BLOCKS_EVENT:  Default exception reporting catch blocks in message handling for
//								protocols to legacy that require MachineControlEvents.
//
//	THIS - this or me
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
#define DEFAULT_MSG_CATCH_BLOCKS_EVENT(THIS, SYS_PRT, IN_MSG, PORT, OUT_MSG_ID)												\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_MSG_ERROR_EVENT((THIS), (SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID));										\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_MSG_EXCEPTION_EVENT((THIS), (SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID));									\
	}																														\
	catch (...)																												\
	{																														\
		REPORT_MSG_CATCH_ALL_EXCEPTION_EVENT((THIS), (SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID));							\
	}																														\

//
// Macro to Q_TRAN from outside of an ActiveHSM state method.  E.g. from
// a catch block in an overriden handle() method.  Assumes me is a pointer
// to an ActiveASM.
//
//	DO NOT CALL THIS FROM INSIDE A STATE METHOD!
//
//  !!!ATTENTION!!!
//		Be carefull with the following macros.  Only the FORWARD macros are
//		meant to be used from within a state method.  The REPORT_HSM macros are
//		designed to be used from a catch OUTSIDE of a state method.  If you
//		are catching from within a state method, just use the non-HSM REPORT
//		macro and Q_TRAN.
//
#define ERROR_TRAN(STATE)									\
	G_LOG_1_TRACE("Q_TRAN ==> %s", #STATE);					\
	me->errorTran(reinterpret_cast<QSTATE>((STATE)));		\
	RoomFW::Q_TRAN_LOG_breakHook();		\

//
// Macros to check current state before doing a state transition.
// In the case of error handling, we (probably) do not want to do
// a 'transition to self' as that causes the current state's exit
// and entry actions to be called.
//
#define ERROR_TRAN_COND(STATE) if (reinterpret_cast<QSTATE>((STATE)) != me->getCurrentState()) ERROR_TRAN((STATE))
#define Q_TRAN_COND(STATE) if (reinterpret_cast<QSTATE>((STATE)) != me->getCurrentState()) Q_TRAN_LOG((STATE))

//
// REPORT_HSM_ERROR:  Default error reporting handler for catch(IError&) in
//						an ActiveHSM state method.  Assumes me is a pointer
//						to an ActiveASM.
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_ERROR(ERROR, PORT, OUT_MSG_ID, ERROR_STATE)																\
{																															\
	REPORT_ERROR(me, (ERROR), (PORT), (OUT_MSG_ID));																		\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_ERROR:  Default error reporting handler for catch(IError&) in message handling in
//						an ActiveHSM state method.  Assumes me is a pointer
//						to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_ERROR(SYS_PRT, IN_MSG, ERROR, PORT, OUT_MSG_ID, ERROR_STATE)													\
{																															\
	REPORT_MSG_ERROR(me, (SYS_PRT), (IN_MSG), (ERROR), (PORT), (OUT_MSG_ID));															\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// FORWARD_HSM_ERROR:  Default error forwarding handler for an ActiveHSM.
//						Assumes me is a pointer to an ActiveASM.
//
//	ERROR_MESSAGE - RoomMessage{* | SP} containing an error payload.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define FORWARD_HSM_ERROR(ERROR_MESSAGE, PORT, OUT_MSG_ID, ERROR_STATE)														\
{																															\
	FORWARD_ERROR(me, (ERROR_MESSAGE), (PORT), (OUT_MSG_ID));																\
	Q_TRAN_COND((ERROR_STATE));																								\
}																															\

//
// REPORT_HSM_ERROR_EVENT:  Default error event reporting handler for catch(IError&) in
//						an ActiveHSM state method.  Assumes me is a pointer
//						to an ActiveASM.
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_ERROR_EVENT(ERROR, PORT, OUT_MSG_ID, ERROR_STATE)														\
{																															\
	REPORT_ERROR_EVENT(me, (ERROR), (PORT), (OUT_MSG_ID));																	\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_ERROR_EVENT:  Default error event reporting handler for catch(IError&) in message handling in
//						an ActiveHSM state method.  Assumes me is a pointer
//						to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	ERROR - IError derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_ERROR_EVENT(SYS_PRT, IN_MSG, ERROR, PORT, OUT_MSG_ID, ERROR_STATE)											\
{																															\
	REPORT_MSG_ERROR_EVENT(me, (SYS_PRT), (IN_MSG), (ERROR), (PORT), (OUT_MSG_ID));													\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// FORWARD_HSM_ERROR_EVENT:  Default error event forwarding handler for an ActiveHSM.
//						Assumes me is a pointer to an ActiveASM.
//
//	ERROR_MESSAGE - RoomMessage{* | SP} containing an error payload.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define FORWARD_HSM_ERROR_EVENT(ERROR_MESSAGE, PORT, OUT_MSG_ID, ERROR_STATE)												\
{																															\
	FORWARD_ERROR_EVENT(me, (ERROR_MESSAGE), (PORT), (OUT_MSG_ID));															\
	Q_TRAN_COND((ERROR_STATE));																								\
}																															\

//
// REPORT_HSM_EXCEPTION:  Default error reporting handler for catch(std::exception) in
//							an ActiveHSM state method.  Assumes me is a pointer
//							to an ActiveASM.
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_EXCEPTION(EXCEPTION, PORT, OUT_MSG_ID, ERROR_STATE)														\
{																															\
	REPORT_EXCEPTION(me, (EXCEPTION), (PORT), (OUT_MSG_ID));																\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_EXCEPTION:  Default error reporting handler for catch(std::exception) in message handling in
//							an ActiveHSM state method.  Assumes me is a pointer
//							to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_EXCEPTION(SYS_PRT, IN_MSG, EXCEPTION, PORT, OUT_MSG_ID, ERROR_STATE)											\
{																															\
	REPORT_MSG_EXCEPTION(me, (SYS_PRT), (IN_MSG), (EXCEPTION), (PORT), (OUT_MSG_ID));													\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_HSM_EXCEPTION_EVENT:  Default error event reporting handler for catch(std::exception) in
//								an ActiveHSM state method.  Assumes me is a pointer
//								to an ActiveASM.
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_EXCEPTION_EVENT(EXCEPTION, PORT, OUT_MSG_ID, ERROR_STATE)												\
{																															\
	REPORT_EXCEPTION_EVENT(me, (EXCEPTION), (PORT), (OUT_MSG_ID));															\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_EXCEPTION_EVENT:  Default error event reporting handler for catch(std::exception) in message handling in
//								an ActiveHSM state method.  Assumes me is a pointer
//								to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	EXCEPTION - std::exception derived reference
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_EXCEPTION_EVENT(SYS_PRT, IN_MSG, EXCEPTION, PORT, OUT_MSG_ID, ERROR_STATE)									\
{																															\
	REPORT_MSG_EXCEPTION_EVENT(me, (SYS_PRT), (IN_MSG), (EXCEPTION), (PORT), (OUT_MSG_ID));											\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_HSM_CATCH_ALL_EXCEPTION:  Default error reporting handler for catch(...) in
//									an ActiveHSM state method.  Assumes me is a pointer
//									to an ActiveASM.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_CATCH_ALL_EXCEPTION(PORT, OUT_MSG_ID, ERROR_STATE)														\
{																															\
	REPORT_CATCH_ALL_EXCEPTION(me, (PORT), (OUT_MSG_ID));																	\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_CATCH_ALL_EXCEPTION:  Default error reporting handler for catch(...) in message handling in
//									an ActiveHSM state method.  Assumes me is a pointer
//									to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_CATCH_ALL_EXCEPTION(SYS_PRT, IN_MSG, PORT, OUT_MSG_ID, ERROR_STATE)											\
{																															\
	REPORT_MSG_CATCH_ALL_EXCEPTION(me, (SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID));														\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_HSM_CATCH_ALL_EXCEPTION_EVENT:  Default error event reporting handler for catch(...) in
//											an ActiveHSM state method.  Assumes me is a pointer
//											to an ActiveASM.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_HSM_CATCH_ALL_EXCEPTION_EVENT(PORT, OUT_MSG_ID, ERROR_STATE)													\
{																															\
	REPORT_CATCH_ALL_EXCEPTION_EVENT(me, (PORT), (OUT_MSG_ID));																\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// REPORT_MSG_HSM_CATCH_ALL_EXCEPTION_EVENT:  Default error event reporting handler for catch(...) in message handling in
//											an ActiveHSM state method.  Assumes me is a pointer
//											to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define REPORT_MSG_HSM_CATCH_ALL_EXCEPTION_EVENT(SYS_PRT, IN_MSG, PORT, OUT_MSG_ID, ERROR_STATE)										\
{																															\
	REPORT_MSG_CATCH_ALL_EXCEPTION_EVENT(me, (SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID));												\
	ERROR_TRAN_COND((ERROR_STATE));																							\
}																															\

//
// DEFAULT_HSM_CATCH_BLOCKS:  Default exception reporting catch blocks.
//								Assumes me is a pointer to an ActiveASM.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define DEFAULT_HSM_CATCH_BLOCKS(PORT, OUT_MSG_ID, ERROR_STATE)																\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_HSM_ERROR(e, (PORT), (OUT_MSG_ID), (ERROR_STATE));															\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_HSM_EXCEPTION(e, (PORT), (OUT_MSG_ID), (ERROR_STATE));														\
	}																														\
	catch(...)																												\
	{																														\
		REPORT_HSM_CATCH_ALL_EXCEPTION((PORT), (OUT_MSG_ID), (ERROR_STATE));												\
	}																														\

//
// DEFAULT_MSG_HSM_CATCH_BLOCKS:  Default exception reporting catch blocks in message handling.
//								Assumes me is a pointer to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define DEFAULT_MSG_HSM_CATCH_BLOCKS(SYS_PRT, IN_MSG, PORT, OUT_MSG_ID, ERROR_STATE)													\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_MSG_HSM_ERROR((SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID), (ERROR_STATE));												\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_MSG_HSM_EXCEPTION((SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID), (ERROR_STATE));											\
	}																														\
	catch(...)																												\
	{																														\
		REPORT_MSG_HSM_CATCH_ALL_EXCEPTION((SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID), (ERROR_STATE));									\
	}																														\

//
// DEFAULT_HSM_CATCH_BLOCKS_EVENT:  Default exception event reporting catch blocks.
//									Assumes me is a pointer to an ActiveASM.
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define DEFAULT_HSM_CATCH_BLOCKS_EVENT(PORT, OUT_MSG_ID, ERROR_STATE)														\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_HSM_ERROR_EVENT(e, (PORT), (OUT_MSG_ID), (ERROR_STATE));														\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_HSM_EXCEPTION_EVENT(e, (PORT), (OUT_MSG_ID), (ERROR_STATE));													\
	}																														\
	catch(...)																												\
	{																														\
		REPORT_HSM_CATCH_ALL_EXCEPTION_EVENT((PORT), (OUT_MSG_ID), (ERROR_STATE));											\
	}																														\

//
// DEFAULT_MSG_HSM_CATCH_BLOCKS_EVENT:  Default exception event reporting catch blocks in message handling.
//									Assumes me is a pointer to an ActiveASM.
//
//	SYS_PRT - SystemManager port.
//
//	IN_MSG - Message being handled when error was thrown
//
//	PORT - Port to send error message out of.
//
//	OUT_MSG_ID - Error message id.  Payload must be ErrorPayload.
//
//	ERROR_STATE - QSTATE error state to transition to.
//
#define DEFAULT_MSG_HSM_CATCH_BLOCKS_EVENT(SYS_PRT, IN_MSG, PORT, OUT_MSG_ID, ERROR_STATE)											\
	catch (ErrorHandling::IError& e)																		\
	{																														\
		REPORT_MSG_HSM_ERROR_EVENT((SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID), (ERROR_STATE));										\
	}																														\
	catch (std::exception& e)																								\
	{																														\
		REPORT_MSG_HSM_EXCEPTION_EVENT((SYS_PRT), (IN_MSG), e, (PORT), (OUT_MSG_ID), (ERROR_STATE));									\
	}																														\
	catch(...)																												\
	{																														\
		REPORT_MSG_HSM_CATCH_ALL_EXCEPTION_EVENT((SYS_PRT), (IN_MSG), (PORT), (OUT_MSG_ID), (ERROR_STATE));							\
	}																														\

